//
// Created by wkm on 2024-04-18.
//

#include "mixcolumns.h"

void mixcolumns::prc_mixcolumns() {
    if (reset) {
        x23_reset = true;
        next_done = waiting_task;
        done = waiting_task; //快速响应
    }

    if (start && done == waiting_task) {
        temp_input_data[0] = input_data_1;
        temp_input_data[1] = input_data_2;
        temp_input_data[2] = input_data_3;
        temp_input_data[3] = input_data_4;
        temp_input_data[4] = input_data_5;
        temp_input_data[5] = input_data_6;
        temp_input_data[6] = input_data_7;
        temp_input_data[7] = input_data_8;
        temp_input_data[8] = input_data_9;
        temp_input_data[9] = input_data_10;
        temp_input_data[10] = input_data_11;
        temp_input_data[11] = input_data_12;
        temp_input_data[12] = input_data_13;
        temp_input_data[13] = input_data_14;
        temp_input_data[14] = input_data_15;
        temp_input_data[15] = input_data_16;
//        x2_done = waiting;  不能双驱动
//        x3_done = waiting;  不能双驱动
        next_done = preparing_task;
        x2_compute_times.write(1);
        x23_reset = false;
    }

    if (done == preparing_task) {
        next_state = row_1_col_1;
        next_done = computing_task;
        x23_prepare = preparing_task;
    }


    if (done == computing_task) {
        if (x23_prepare == preparing_task) {
            x23_reset = false;
            x23_prepare = computing_task;
        } else if (x23_prepare == computing_task) {
            switch (state) {
                // 第一列
                case row_1_col_1:
                    x2_input_data = temp_input_data[0];
                    x3_input_data = temp_input_data[1];
                    x23_start = true; //必须在start之前准备好数据
                    if (x2_done == task_finished && x3_done == task_finished) {
                        x23_start = false;
                        temp_result[0] = x2_output_data.read() ^
                                         x3_output_data.read() ^
                                         temp_input_data[2] ^
                                         temp_input_data[3];
//                        cout << hex << "x2_output_data: " << x2_output_data.read() << endl;
//                        cout << hex << "x3_output_data: " << x3_output_data.read() << endl;
//                        cout << hex << "temp_input_data[2]: " << temp_input_data[2] << endl;
//                        cout << hex << "temp_input_data[3]: " << temp_input_data[3] << endl;
//                        cout << hex << "temp_result[0]: " << temp_result[0] << endl;
                        next_state = row_2_col_1;
                        x23_reset = true;
                        x23_prepare = preparing_task;
                    }
                    break;
                case row_2_col_1:
                    x2_input_data = temp_input_data[1];
                    x3_input_data = temp_input_data[2];
                    x23_start = true; //必须在start之前准备好数据
                    if (x2_done == task_finished && x3_done == task_finished) {
                        x23_start = false;
                        temp_result[1] = temp_input_data[0] ^
                                         x2_output_data.read() ^
                                         x3_output_data.read() ^
                                         temp_input_data[3];
//                        cout << hex << "temp_input_data[0]: " << temp_input_data[0] << endl;
//                        cout << hex << "x2_output_data: " << x2_output_data.read() << endl;
//                        cout << hex << "x3_output_data: " << x3_output_data.read() << endl;
//                        cout << hex << "temp_input_data[3]: " << temp_input_data[3] << endl;
//                        cout << hex << "temp_result[1]: " << temp_result[1] << endl;
                        next_state = row_3_col_1;
                        x23_reset = true;
                        x23_prepare = preparing_task;
                    }
                    break;
                case row_3_col_1:
                    x2_input_data = temp_input_data[2];
                    x3_input_data = temp_input_data[3];
                    x23_start = true; //必须在start之前准备好数据
                    if (x2_done == task_finished && x3_done == task_finished) {
                        x23_start = false;
                        temp_result[2] = temp_input_data[0] ^
                                         temp_input_data[1] ^
                                         x2_output_data.read() ^
                                         x3_output_data.read();
                        next_state = row_4_col_1;
                        x23_reset = true;
                        x23_prepare = preparing_task;
                    }
                    break;
                case row_4_col_1:
                    x2_input_data = temp_input_data[3];
                    x3_input_data = temp_input_data[0];
                    x23_start = true; //必须在start之前准备好数据
                    if (x2_done == task_finished && x3_done == task_finished) {
                        x23_start = false;
                        temp_result[3] = x3_output_data.read() ^
                                         temp_input_data[1] ^
                                         temp_input_data[2] ^
                                         x2_output_data.read();
                        next_state = row_1_col_2;
                        x23_reset = true;
                        x23_prepare = preparing_task;
                    }
                    break;
                    //第二列
                case row_1_col_2:
                    x2_input_data = temp_input_data[4];
                    x3_input_data = temp_input_data[5];
                    x23_start = true; //必须在start之前准备好数据
                    if (x2_done == task_finished && x3_done == task_finished) {
                        x23_start = false;
                        temp_result[4] = x2_output_data.read() ^
                                         x3_output_data.read() ^
                                         temp_input_data[6] ^
                                         temp_input_data[7];
                        next_state = row_2_col_2;
                        x23_reset = true;
                        x23_prepare = preparing_task;
                    }
                    break;
                case row_2_col_2:
                    x2_input_data = temp_input_data[5];
                    x3_input_data = temp_input_data[6];
                    x23_start = true; //必须在start之前准备好数据
                    if (x2_done == task_finished && x3_done == task_finished) {
                        x23_start = false;
                        temp_result[5] = temp_input_data[4] ^
                                         x2_output_data.read() ^
                                         x3_output_data.read() ^
                                         temp_input_data[7];
                        next_state = row_3_col_2;
                        x23_reset = true;
                        x23_prepare = preparing_task;
                    }
                    break;
                case row_3_col_2:
                    x2_input_data = temp_input_data[6];
                    x3_input_data = temp_input_data[7];
                    x23_start = true; //必须在start之前准备好数据
                    if (x2_done == task_finished && x3_done == task_finished) {
                        x23_start = false;
                        temp_result[6] = temp_input_data[4] ^
                                         temp_input_data[5] ^
                                         x2_output_data.read() ^
                                         x3_output_data.read();
                        next_state = row_4_col_2;
                        x23_reset = true;
                        x23_prepare = preparing_task;
                    }
                    break;
                case row_4_col_2:
                    x2_input_data = temp_input_data[7];
                    x3_input_data = temp_input_data[4];
                    x23_start = true; //必须在start之前准备好数据
                    if (x2_done == task_finished && x3_done == task_finished) {
                        x23_start = false;
                        temp_result[7] = x3_output_data.read() ^
                                         temp_input_data[5] ^
                                         temp_input_data[6] ^
                                         x2_output_data.read();
                        next_state = row_1_col_3;
                        x23_reset = true;
                        x23_prepare = preparing_task;
                    }
                    break;
                    //第三列
                case row_1_col_3:
                    x2_input_data = temp_input_data[8];
                    x3_input_data = temp_input_data[9];
                    x23_start = true; //必须在start之前准备好数据
                    if (x2_done == task_finished && x3_done == task_finished) {
                        x23_start = false;
                        temp_result[8] = x2_output_data.read() ^
                                         x3_output_data.read() ^
                                         temp_input_data[10] ^
                                         temp_input_data[11];
                        next_state = row_2_col_3;
                        x23_reset = true;
                        x23_prepare = preparing_task;
                    }
                    break;
                case row_2_col_3:
                    x2_input_data = temp_input_data[9];
                    x3_input_data = temp_input_data[10];
                    x23_start = true; //必须在start之前准备好数据
                    if (x2_done == task_finished && x3_done == task_finished) {
                        x23_start = false;
                        temp_result[9] = temp_input_data[8] ^
                                         x2_output_data.read() ^
                                         x3_output_data.read() ^
                                         temp_input_data[11];
                        next_state = row_3_col_3;
                        x23_reset = true;
                        x23_prepare = preparing_task;
                    }
                    break;
                case row_3_col_3:
                    x2_input_data = temp_input_data[10];
                    x3_input_data = temp_input_data[11];
                    x23_start = true; //必须在start之前准备好数据
                    if (x2_done == task_finished && x3_done == task_finished) {
                        x23_start = false;
                        temp_result[10] = temp_input_data[8] ^
                                          temp_input_data[9] ^
                                          x2_output_data.read() ^
                                          x3_output_data.read();
                        next_state = row_4_col_3;
                        x23_reset = true;
                        x23_prepare = preparing_task;
                    }
                    break;
                case row_4_col_3:
                    x2_input_data = temp_input_data[11];
                    x3_input_data = temp_input_data[8];
                    x23_start = true; //必须在start之前准备好数据
                    if (x2_done == task_finished && x3_done == task_finished) {
                        x23_start = false;
                        temp_result[11] = x3_output_data.read() ^
                                          temp_input_data[9] ^
                                          temp_input_data[10] ^
                                          x2_output_data.read();
                        next_state = row_1_col_4;
                        x23_reset = true;
                        x23_prepare = preparing_task;
                    }
                    break;
                    //第四列
                case row_1_col_4:
                    x2_input_data = temp_input_data[12];
                    x3_input_data = temp_input_data[13];
                    x23_start = true; //必须在start之前准备好数据
                    if (x2_done == task_finished && x3_done == task_finished) {
                        x23_start = false;
                        temp_result[12] = x2_output_data.read() ^
                                          x3_output_data.read() ^
                                          temp_input_data[14] ^
                                          temp_input_data[15];
                        next_state = row_2_col_4;
                        x23_reset = true;
                        x23_prepare = preparing_task;
                    }
                    break;
                case row_2_col_4:
                    x2_input_data = temp_input_data[13];
                    x3_input_data = temp_input_data[14];
                    x23_start = true; //必须在start之前准备好数据
                    if (x2_done == task_finished && x3_done == task_finished) {
                        x23_start = false;
                        temp_result[13] = temp_input_data[12] ^
                                          x2_output_data.read() ^
                                          x3_output_data.read() ^
                                          temp_input_data[15];
                        next_state = row_3_col_4;
                        x23_reset = true;
                        x23_prepare = preparing_task;
                    }
                    break;
                case row_3_col_4:
                    x2_input_data = temp_input_data[14];
                    x3_input_data = temp_input_data[15];
                    x23_start = true; //必须在start之前准备好数据
                    if (x2_done == task_finished && x3_done == task_finished) {
                        x23_start = false;
                        temp_result[14] = temp_input_data[12] ^
                                          temp_input_data[13] ^
                                          x2_output_data.read() ^
                                          x3_output_data.read();
                        next_state = row_4_col_4;
                        x23_reset = true;
                        x23_prepare = preparing_task;
                    }
                    break;
                case row_4_col_4:
                    x2_input_data = temp_input_data[15];
                    x3_input_data = temp_input_data[12];
                    x23_start = true; //必须在start之前准备好数据
                    if (x2_done == task_finished && x3_done == task_finished) {
                        x23_start = false;
                        temp_result[15] = x3_output_data.read() ^
                                          temp_input_data[13] ^
                                          temp_input_data[14] ^
                                          x2_output_data.read();
                        next_state = OVER;
                        x23_reset = true;
                        x23_prepare = preparing_task;
                    }
                    break;
                default:
                    next_done = task_finished;
                    x23_prepare = task_finished;
//                    cout << "res:"
//                         << temp_result[0] << "," << temp_result[1] << "," << temp_result[2] << "," << temp_result[3]
//                         << ","
//                         << temp_result[4] << "," << temp_result[5] << "," << temp_result[6] << "," << temp_result[7]
//                         << ","
//                         << temp_result[8] << "," << temp_result[9] << "," << temp_result[10] << "," << temp_result[11]
//                         << ","
//                         << temp_result[12] << "," << temp_result[13] << "," << temp_result[14] << ","
//                         << temp_result[15]
//                         << endl;
                    // 这种情况属于已经完成
                    out_data_1 = temp_result[0];
                    out_data_2 = temp_result[1];
                    out_data_3 = temp_result[2];
                    out_data_4 = temp_result[3];
                    out_data_5 = temp_result[4];
                    out_data_6 = temp_result[5];
                    out_data_7 = temp_result[6];
                    out_data_8 = temp_result[7];
                    out_data_9 = temp_result[8];
                    out_data_10 = temp_result[9];
                    out_data_11 = temp_result[10];
                    out_data_12 = temp_result[11];
                    out_data_13 = temp_result[12];
                    out_data_14 = temp_result[13];
                    out_data_15 = temp_result[14];
                    out_data_16 = temp_result[15];
                    break;
            }
        }
    }

    state = next_state;
    done = next_done;
}